use super::{MhSha1BlockFunction, ISAL_HASH_SEGS, ISAL_SHA1_BLOCK_SIZE, ISAL_SHA1_DIGEST_WORDS};

#[link(name = "isal_crypto_mh_sha")]
unsafe extern "C" {
    fn _mh_sha1_block_sse(input_data: *const u8, mh_sha1_segs_digests: *mut u32, aligned_frame_buffer: *mut u8, num_blocks: u32);
    fn _mh_sha1_block_avx(input_data: *const u8, mh_sha1_segs_digests: *mut u32, aligned_frame_buffer: *mut u8, num_blocks: u32);
    fn _mh_sha1_block_avx2(input_data: *const u8, mh_sha1_segs_digests: *mut u32, aligned_frame_buffer: *mut u8, num_blocks: u32);
    fn _mh_sha1_block_avx512(input_data: *const u8, mh_sha1_segs_digests: *mut u32, aligned_frame_buffer: *mut u8, num_blocks: u32);
}


#[repr(C, align(64))]
#[derive(Clone, Debug)]
pub struct MhSha1AvxWordFrameBuffer([u8;ISAL_HASH_SEGS*ISAL_SHA1_BLOCK_SIZE]);

impl Default for MhSha1AvxWordFrameBuffer {
    fn default() -> Self {
        Self([0u8;ISAL_HASH_SEGS*ISAL_SHA1_BLOCK_SIZE])
    }
}


#[derive(Debug, Clone, PartialEq, Copy, Hash, Eq, Default)]
pub struct MhSha1Sse;

impl MhSha1BlockFunction for MhSha1Sse {
    type FrameBuffer = MhSha1AvxWordFrameBuffer;
    fn mh_sha1_block_function(input_data: &[u8], mh_sha1_segs_digests: &mut [[u32;ISAL_HASH_SEGS];ISAL_SHA1_DIGEST_WORDS], aligned_frame_buffer: &mut Self::FrameBuffer, num_blocks: u32) {
        unsafe { _mh_sha1_block_sse(&input_data[0] as *const u8, &mut mh_sha1_segs_digests[0][0] as *mut u32, &mut aligned_frame_buffer.0[0] as *mut u8, num_blocks); }
    }
}

#[derive(Debug, Clone, PartialEq, Copy, Hash, Eq, Default)]
pub struct MhSha1Avx;

impl MhSha1BlockFunction for MhSha1Avx {
    type FrameBuffer = MhSha1AvxWordFrameBuffer;
    fn mh_sha1_block_function(input_data: &[u8], mh_sha1_segs_digests: &mut [[u32;ISAL_HASH_SEGS];ISAL_SHA1_DIGEST_WORDS], aligned_frame_buffer: &mut Self::FrameBuffer, num_blocks: u32) {
        unsafe { _mh_sha1_block_avx(&input_data[0] as *const u8, &mut mh_sha1_segs_digests[0][0] as *mut u32, &mut aligned_frame_buffer.0[0] as *mut u8, num_blocks); }
    }
}


#[derive(Debug, Clone, PartialEq, Copy, Hash, Eq, Default)]
pub struct MhSha1Avx2;

impl MhSha1BlockFunction for MhSha1Avx2 {
    type FrameBuffer = MhSha1AvxWordFrameBuffer;
    fn mh_sha1_block_function(input_data: &[u8], mh_sha1_segs_digests: &mut [[u32;ISAL_HASH_SEGS];ISAL_SHA1_DIGEST_WORDS], aligned_frame_buffer: &mut Self::FrameBuffer, num_blocks: u32) {
        unsafe { _mh_sha1_block_avx2(&input_data[0] as *const u8, &mut mh_sha1_segs_digests[0][0] as *mut u32, &mut aligned_frame_buffer.0[0] as *mut u8, num_blocks); }
    }
}


#[derive(Debug, Clone, PartialEq, Copy, Hash, Default)]
pub struct MhSha1Avx512;

impl MhSha1BlockFunction for MhSha1Avx512 {
    type FrameBuffer = MhSha1AvxWordFrameBuffer;
    fn mh_sha1_block_function(input_data: &[u8], mh_sha1_segs_digests: &mut [[u32;ISAL_HASH_SEGS];ISAL_SHA1_DIGEST_WORDS], aligned_frame_buffer: &mut Self::FrameBuffer, num_blocks: u32) {
        unsafe { _mh_sha1_block_avx512(&input_data[0] as *const u8, &mut mh_sha1_segs_digests[0][0] as *mut u32, &mut aligned_frame_buffer.0[0] as *mut u8, num_blocks); }
    }
}

